//
//  NSData+AES.m
//  CLExtension
//
//  Created by CharlieLiao on 2017/8/2.
//  Copyright © 2017年 Charlie. All rights reserved.
//

#import "CLAES.h"
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (CLAES)

/// AES加密 iv=nil SecurityPaddingZero SecurityModeCBC
- (NSData*)encryptAESWithKey:(NSString*)key
{
    return [self encryptAESWithKey:key andIV:nil padding:SecurityPaddingZero mode:SecurityModeCBC];
}


/// AES解密 iv=nil SecurityPaddingZero SecurityModeCBC
- (NSData*)decryptAESWithKey:(NSString*)key
{
    return [self decryptAESWithKey:key andIV:nil padding:SecurityPaddingZero mode:SecurityModeCBC];
}

/// AES加密
- (NSData*)encryptAESWithKey:(NSString*)key andIV:(NSString *)iv padding:(SecurityPadding)padding mode:(SecurityMode)mode
{
    return [self AES:kCCEncrypt key:key andIV:iv padding:padding mode:mode];
}

/// AES解密
- (NSData*)decryptAESWithKey:(NSString*)key andIV:(NSString *)iv padding:(SecurityPadding)padding mode:(SecurityMode)mode
{
    return [self AES:kCCDecrypt key:key andIV:iv padding:padding mode:mode];
}

- (NSData*)AES:(CCOperation)operation key:(NSString*)key andIV:(NSString *)iv padding:(SecurityPadding)padding mode:(SecurityMode)mode
{
    // 算法模式
    CCOptions options;
    switch (mode) {
        case SecurityModeCBC: // Default is CBC.
            options = 0;
            break;
        case SecurityModeECB:
            options = kCCOptionECBMode;
            break;
    }
    
    //
    size_t rawSize = self.length;
    size_t dataSize = rawSize;
    
    // 填充模式
    switch (padding) {
        case SecurityPaddingZero: {  // 需要填充0
            uint remainder = rawSize % kCCBlockSizeAES128;
            if (remainder > 0)
                dataSize += kCCBlockSizeAES128 - remainder;
        }
            break;
            
        case SecurityPaddingPKCS7:
            options |= kCCOptionPKCS7Padding;
            break;
    }
    
    //
    char *dataPtr = malloc(dataSize);
    memset(dataPtr, 0x0, dataSize);
    memcpy(dataPtr, self.bytes, rawSize);

//    char dataPtr[dataSize];
//    memcpy(dataPtr, self.bytes, rawSize);
//    memset(&dataPtr[rawSize], 0, dataSize-rawSize);
    
    size_t bufferPtrSize = (dataSize + kCCBlockSizeAES128) & ~(kCCBlockSizeAES128 - 1);
//    uint8_t bufferPtr[bufferPtrSize];
    char *bufferPtr = malloc(bufferPtrSize);
//    memset(bufferPtr, 0x0, bufferPtrSize);
    
    size_t movedBytes = 0;
    
    CCCryptorStatus ccStatus = CCCrypt(operation,
                                       kCCAlgorithmAES,
                                       options,
                                       key.UTF8String,   //key
                                       kCCKeySizeAES256,
                                       iv.UTF8String,    //iv
                                       dataPtr,
                                       dataSize,
                                       bufferPtr,
                                       bufferPtrSize,
                                       &movedBytes);
    
        free(dataPtr);
    
//    NSData *rData;
    if (ccStatus == kCCSuccess)
        return [NSData dataWithBytesNoCopy:bufferPtr length:movedBytes freeWhenDone:true];
//        rData = [NSData dataWithBytes:bufferPtr length:movedBytes];

//    return rData;
    return nil;
}

@end
